home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mmdf / libz / zic.c < prev   
Encoding:
C/C++ Source or Header  |  1989-09-10  |  31.9 KB  |  1,561 lines

  1. #
  2.  
  3. #include "stdio.h"
  4.  
  5. #ifndef lint
  6. #ifndef NOID
  7. static char    sccsid[] = "@(#)zic.c    3.1";
  8. #endif /* !NOID */
  9. #endif /* !lint */
  10.  
  11. #include "tzfile.h"
  12. #include "ctype.h"
  13. #include "sys/types.h"
  14. #include "sys/stat.h"
  15. #include "time.h"
  16.  
  17. #ifndef BUFSIZ
  18. #define BUFSIZ    1024
  19. #endif
  20.  
  21. #ifndef TRUE
  22. #define TRUE    1
  23. #define FALSE    0
  24. #endif
  25.  
  26. extern char *    icpyalloc();
  27. extern char *    imalloc();
  28. extern char *    irealloc();
  29. extern char *    optarg;
  30. extern int    optind;
  31. extern FILE *    popen();
  32. extern char *    scheck();
  33. #if defined(USG) || defined(SYS5)    /* Added SYS5. ECB 10/88 */
  34. extern char *    sprintf();
  35. #endif /* !USG */
  36. extern char *    strcat();
  37. extern char *    index();
  38. extern char *    strcpy();
  39.  
  40. static        addtt();
  41. static        addtype();
  42. static        associate();
  43. static int    charcnt;
  44. static        ciequal();
  45. static long    eitol();
  46. static int    errors;
  47. static char *    filename;
  48. static char **    getfields();
  49. static long    gethms();
  50. static        infile();
  51. static        inlink();
  52. static        inrule();
  53. static        inzcont();
  54. static        inzone();
  55. static        inzsub();
  56. static int    linenum;
  57. static        lowerit();
  58. static time_t    max_time;
  59. static int    max_year;
  60. static time_t    min_time;
  61. static int    min_year;
  62. static        mkdirs();
  63. static        newabbr();
  64. static int    noise;
  65. static        nondunlink();
  66. static long    oadd();
  67. static        outzone();
  68. static char *    progname;
  69. static char *    rfilename;
  70. static int    rlinenum;
  71. static time_t    rpytime();
  72. static        rulesub();
  73. static        setboundaries();
  74. static time_t    tadd();
  75. static int    timecnt;
  76. static int    tt_signed;
  77. static int    typecnt;
  78. static        yearistype();
  79.  
  80. /*
  81. ** Line codes.
  82. */
  83.  
  84. #define LC_RULE        0
  85. #define LC_ZONE        1
  86. #define LC_LINK        2
  87.  
  88. /*
  89. ** Which fields are which on a Zone line.
  90. */
  91.  
  92. #define ZF_NAME        1
  93. #define ZF_GMTOFF    2
  94. #define ZF_RULE        3
  95. #define ZF_FORMAT    4
  96. #define ZF_UNTILYEAR    5
  97. #define ZF_UNTILMONTH    6
  98. #define ZF_UNTILDAY    7
  99. #define ZF_UNTILTIME    8
  100. #define ZONE_MINFIELDS    5
  101. #define ZONE_MAXFIELDS    9
  102.  
  103. /*
  104. ** Which fields are which on a Zone continuation line.
  105. */
  106.  
  107. #define ZFC_GMTOFF    0
  108. #define ZFC_RULE    1
  109. #define ZFC_FORMAT    2
  110. #define ZFC_UNTILYEAR    3
  111. #define ZFC_UNTILMONTH    4
  112. #define ZFC_UNTILDAY    5
  113. #define ZFC_UNTILTIME    6
  114. #define ZONEC_MINFIELDS    3
  115. #define ZONEC_MAXFIELDS    7
  116.  
  117. /*
  118. ** Which files are which on a Rule line.
  119. */
  120.  
  121. #define RF_NAME        1
  122. #define RF_LOYEAR    2
  123. #define RF_HIYEAR    3
  124. #define RF_COMMAND    4
  125. #define RF_MONTH    5
  126. #define RF_DAY        6
  127. #define RF_TOD        7
  128. #define RF_STDOFF    8
  129. #define RF_ABBRVAR    9
  130. #define RULE_FIELDS    10
  131.  
  132. /*
  133. ** Which fields are which on a Link line.
  134. */
  135.  
  136. #define LF_FROM        1
  137. #define LF_TO        2
  138. #define LINK_FIELDS    3
  139.  
  140. struct rule {
  141.     char *    r_filename;
  142.     int    r_linenum;
  143.     char *    r_name;
  144.  
  145.     int    r_loyear;    /* for example, 1986 */
  146.     int    r_hiyear;    /* for example, 1986 */
  147.     char *    r_yrtype;
  148.  
  149.     int    r_month;    /* 0..11 */
  150.  
  151.     int    r_dycode;    /* see below */
  152.     int    r_dayofmonth;
  153.     int    r_wday;
  154.  
  155.     long    r_tod;        /* time from midnight */
  156.     int    r_todisstd;    /* above is standard time if TRUE */
  157.                 /* above is wall clock time if FALSE */
  158.     long    r_stdoff;    /* offset from standard time */
  159.     char *    r_abbrvar;    /* variable part of time zone abbreviation */
  160.  
  161.     int    r_todo;        /* a rule to do (used in outzone) */
  162.     time_t    r_temp;        /* used in outzone */
  163. };
  164.  
  165. /*
  166. **    r_dycode        r_dayofmonth    r_wday
  167. */
  168. #define DC_DOM        0    /* 1..31 */    /* unused */
  169. #define DC_DOWGEQ    1    /* 1..31 */    /* 0..6 (Sun..Sat) */
  170. #define DC_DOWLEQ    2    /* 1..31 */    /* 0..6 (Sun..Sat) */
  171.  
  172. /*
  173. ** Year synonyms.
  174. */
  175.  
  176. #define YR_MINIMUM    0
  177. #define YR_MAXIMUM    1
  178. #define YR_ONLY        2
  179.  
  180. static struct rule *    rules;
  181. static int        nrules;    /* number of rules */
  182.  
  183. struct zone {
  184.     char *        z_filename;
  185.     int        z_linenum;
  186.  
  187.     char *        z_name;
  188.     long        z_gmtoff;
  189.     char *        z_rule;
  190.     char *        z_format;
  191.  
  192.     long        z_stdoff;
  193.  
  194.     struct rule *    z_rules;
  195.     int        z_nrules;
  196.  
  197.     struct rule    z_untilrule;
  198.     time_t        z_untiltime;
  199. };
  200.  
  201. static struct zone *    zones;
  202. static int        nzones;    /* number of zones */
  203.  
  204. struct link {
  205.     char *        l_filename;
  206.     int        l_linenum;
  207.     char *        l_from;
  208.     char *        l_to;
  209. };
  210.  
  211. static struct link *    links;
  212. static int        nlinks;
  213.  
  214. struct lookup {
  215.     char *        l_word;
  216.     int        l_value;
  217. };
  218.  
  219. static struct lookup *    byword();
  220.  
  221. static struct lookup    line_codes[] = {
  222.     "Rule",        LC_RULE,
  223.     "Zone",        LC_ZONE,
  224.     "Link",        LC_LINK,
  225.     NULL,        0
  226. };
  227.  
  228. static struct lookup    mon_names[] = {
  229.     "January",    TM_JANUARY,
  230.     "February",    TM_FEBRUARY,
  231.     "March",    TM_MARCH,
  232.     "April",    TM_APRIL,
  233.     "May",        TM_MAY,
  234.     "June",        TM_JUNE,
  235.     "July",        TM_JULY,
  236.     "August",    TM_AUGUST,
  237.     "September",    TM_SEPTEMBER,
  238.     "October",    TM_OCTOBER,
  239.     "November",    TM_NOVEMBER,
  240.     "December",    TM_DECEMBER,
  241.     NULL,        0
  242. };
  243.  
  244. static struct lookup    wday_names[] = {
  245.     "Sunday",    TM_SUNDAY,
  246.     "Monday",    TM_MONDAY,
  247.     "Tuesday",    TM_TUESDAY,
  248.     "Wednesday",    TM_WEDNESDAY,
  249.     "Thursday",    TM_THURSDAY,
  250.     "Friday",    TM_FRIDAY,
  251.     "Saturday",    TM_SATURDAY,
  252.     NULL,        0
  253. };
  254.  
  255. static struct lookup    lasts[] = {
  256.     "last-Sunday",        TM_SUNDAY,
  257.     "last-Monday",        TM_MONDAY,
  258.     "last-Tuesday",        TM_TUESDAY,
  259.     "last-Wednesday",    TM_WEDNESDAY,
  260.     "last-Thursday",    TM_THURSDAY,
  261.     "last-Friday",        TM_FRIDAY,
  262.     "last-Saturday",    TM_SATURDAY,
  263.     NULL,            0
  264. };
  265.  
  266. static struct lookup    begin_years[] = {
  267.     "minimum",        YR_MINIMUM,
  268.     "maximum",        YR_MAXIMUM,
  269.     NULL,            0
  270. };
  271.  
  272. static struct lookup    end_years[] = {
  273.     "minimum",        YR_MINIMUM,
  274.     "maximum",        YR_MAXIMUM,
  275.     "only",            YR_ONLY,
  276.     NULL,            0
  277. };
  278.  
  279. static int    len_months[2][MONS_PER_YEAR] = {
  280.     31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
  281.     31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  282. };
  283.  
  284. static int    len_years[2] = {
  285.     DAYS_PER_NYEAR, DAYS_PER_LYEAR
  286. };
  287.  
  288. static time_t        ats[TZ_MAX_TIMES];
  289. static unsigned char    types[TZ_MAX_TIMES];
  290. static long        gmtoffs[TZ_MAX_TYPES];
  291. static char        isdsts[TZ_MAX_TYPES];
  292. static char        abbrinds[TZ_MAX_TYPES];
  293. static char        chars[TZ_MAX_CHARS];
  294.  
  295. /*
  296. ** Memory allocation.
  297. */
  298.  
  299. static char *
  300. memcheck(ptr)
  301. char *    ptr;
  302. {
  303.     if (ptr == NULL) {
  304.         perror(progname);
  305.         exit(1);
  306.     }
  307.     return ptr;
  308. }
  309.  
  310. #define emalloc(size)        memcheck(imalloc(size))
  311. #define erealloc(ptr, size)    memcheck(irealloc(ptr, size))
  312. #define ecpyalloc(ptr)        memcheck(icpyalloc(ptr))
  313.  
  314. /*
  315. ** Error handling.
  316. */
  317.  
  318. static
  319. eats(name, num, rname, rnum)
  320. char *    name;
  321. char *    rname;
  322. {
  323.     filename = name;
  324.     linenum = num;
  325.     rfilename = rname;
  326.     rlinenum = rnum;
  327. }
  328.  
  329. static
  330. eat(name, num)
  331. char *    name;
  332. {
  333.     eats(name, num, (char *) NULL, -1);
  334. }
  335.  
  336. static
  337. error(string)
  338. char *    string;
  339. {
  340.     /*
  341.     ** Match the format of "cc" to allow sh users to
  342.     **     zic ... 2>&1 | error -t "*" -v
  343.     ** on BSD systems.
  344.     */
  345.     (void) fprintf(stderr, "\"%s\", line %d: %s",
  346.         filename, linenum, string);
  347.     if (rfilename != NULL)
  348.         (void) fprintf(stderr, " (rule from \"%s\", line %d)",
  349.             rfilename, rlinenum);
  350.     (void) fprintf(stderr, "\n");
  351.     ++errors;
  352. }
  353.  
  354. static
  355. usage()
  356. {
  357.     (void) fprintf(stderr,
  358. "%s: usage is %s [ -v ] [ -l localtime ] [ -d directory ] [ filename ... ]\n",
  359.         progname, progname);
  360.     exit(1);
  361. }
  362.  
  363. static char *    lcltime = NULL;
  364. static char *    directory = NULL;
  365.  
  366. main(argc, argv)
  367. int    argc;
  368. char *    argv[];
  369. {
  370.     register int    i, j;
  371.     register int    c;
  372.  
  373. #ifdef unix
  374.     umask(umask(022) | 022);
  375. #endif
  376.     progname = argv[0];
  377.     while ((c = getopt(argc, argv, "d:l:v")) != EOF)
  378.         switch (c) {
  379.             default:
  380.                 usage();
  381.             case 'd':
  382.                 if (directory == NULL)
  383.                     directory = optarg;
  384.                 else {
  385.                     (void) fprintf(stderr,
  386. "%s: More than one -d option specified\n",
  387.                         progname);
  388.                     exit(1);
  389.                 }
  390.                 break;
  391.             case 'l':
  392.                 if (lcltime == NULL)
  393.                     lcltime = optarg;
  394.                 else {
  395.                     (void) fprintf(stderr,
  396. "%s: More than one -l option specified\n",
  397.                         progname);
  398.                     exit(1);
  399.                 }
  400.                 break;
  401.             case 'v':
  402.                 noise = TRUE;
  403.                 break;
  404.         }
  405.     if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
  406.         usage();    /* usage message by request */
  407.     if (directory == NULL)
  408.         directory = TZDIR;
  409.  
  410.     setboundaries();
  411.  
  412.     zones = (struct zone *) emalloc(0);
  413.     rules = (struct rule *) emalloc(0);
  414.     links = (struct link *) emalloc(0);
  415.     for (i = optind; i < argc; ++i)
  416.         infile(argv[i]);
  417.     if (errors)
  418.         exit(1);
  419.     associate();
  420.     for (i = 0; i < nzones; i = j) {
  421.         /*
  422.          * Find the next non-continuation zone entry.
  423.          */
  424.         for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
  425.             ;
  426.         outzone(&zones[i], j - i);
  427.     }
  428.     /*
  429.     ** We'll take the easy way out on this last part.
  430.     */
  431.     if (chdir(directory) != 0) {
  432.         (void) fprintf(stderr, "%s: Can't chdir to ", progname);
  433.         perror(directory);
  434.         exit(1);
  435.     }
  436.     for (i = 0; i < nlinks; ++i) {
  437.         nondunlink(links[i].l_to);
  438.         if (link(links[i].l_from, links[i].l_to) != 0) {
  439.             (void) fprintf(stderr, "%s: Can't link %s to ",
  440.                 progname, links[i].l_from);
  441.             perror(links[i].l_to);
  442.             exit(1);
  443.         }
  444.     }
  445.     if (lcltime != NULL) {
  446.         nondunlink(TZDEFAULT);
  447.         if (link(lcltime, TZDEFAULT) != 0) {
  448.             (void) fprintf(stderr, "%s: Can't link %s to ",
  449.                 progname, lcltime);
  450.             perror(TZDEFAULT);
  451.             exit(1);
  452.         }
  453.     }
  454.     exit((errors == 0) ? 0 : 1);
  455. }
  456.  
  457. static
  458. setboundaries()
  459. {
  460.     register time_t     bit;
  461.  
  462.     for (bit = 1; bit > 0; bit <<= 1)
  463.         ;
  464.     if (bit == 0) {        /* time_t is an unsigned type */
  465.         tt_signed = FALSE;
  466.         min_time = 0;
  467.         max_time = ~(time_t) 0;
  468.     } else {
  469.         tt_signed = TRUE;
  470.         min_time = bit;
  471.         max_time = bit;
  472.         ++max_time;
  473.         max_time = -max_time;
  474.     }
  475.     min_year = TM_YEAR_BASE + gmtime(&min_time)->tm_year;
  476.     max_year = TM_YEAR_BASE + gmtime(&max_time)->tm_year;
  477. }
  478.  
  479. /*
  480. ** We get to be careful here since there's a fair chance of root running us.
  481. */
  482.  
  483. static
  484. nondunlink(name)
  485. char *    name;
  486. {
  487.     struct stat    s;
  488.  
  489.     if (stat(name, &s) != 0)
  490.         return;
  491.     if ((s.st_mode & S_IFMT) == S_IFDIR)
  492.         return;
  493.     (void) unlink(name);
  494. }
  495.  
  496. /*
  497. ** Associate sets of rules with zones.
  498. */
  499.  
  500. /*
  501. ** Sort by rule name.
  502. */
  503.  
  504. static
  505. rcomp(cp1, cp2)
  506. char *    cp1;
  507. char *    cp2;
  508. {
  509.     return strcmp(((struct rule *) cp1)->r_name,
  510.         ((struct rule *) cp2)->r_name);
  511. }
  512.  
  513. static
  514. associate()
  515. {
  516.     register struct zone *    zp;
  517.     register struct rule *    rp;
  518.     register int        base, out;
  519.     register int        i;
  520.  
  521.     if (nrules != 0)
  522.         (void) qsort((char *) rules, nrules, sizeof *rules, rcomp);
  523.     for (i = 0; i < nzones; ++i) {
  524.         zp = &zones[i];
  525.         zp->z_rules = NULL;
  526.         zp->z_nrules = 0;
  527.     }
  528.     for (base = 0; base < nrules; base = out) {
  529.         rp = &rules[base];
  530.         for (out = base + 1; out < nrules; ++out)
  531.             if (strcmp(rp->r_name, rules[out].r_name) != 0)
  532.                 break;
  533.         for (i = 0; i < nzones; ++i) {
  534.             zp = &zones[i];
  535.             if (strcmp(zp->z_rule, rp->r_name) != 0)
  536.                 continue;
  537.             zp->z_rules = rp;
  538.             zp->z_nrules = out - base;
  539.         }
  540.     }
  541.     for (i = 0; i < nzones; ++i) {
  542.         zp = &zones[i];
  543.         if (zp->z_nrules == 0) {
  544.             /*
  545.             ** Maybe we have a local standard time offset.
  546.             */
  547.             eat(zp->z_filename, zp->z_linenum);
  548.             zp->z_stdoff = gethms(zp->z_rule, "unruly zone", TRUE);
  549.             /*
  550.             ** Note, though, that if there's no rule,
  551.             ** a '%s' in the format is a bad thing.
  552.             */
  553.             if (index(zp->z_format, '%') != 0)
  554.                 error("%s in ruleless zone");
  555.         }
  556.     }
  557.     if (errors)
  558.         exit(1);
  559. }
  560.  
  561. static
  562. infile(name)
  563. char *    name;
  564. {
  565.     register FILE *            fp;
  566.     register char **        fields;
  567.     register char *            cp;
  568.     register struct lookup *    lp;
  569.     register int            nfields;
  570.     register int            wantcont;
  571.     register int            num;
  572.     char                buf[BUFSIZ];
  573.  
  574.     if (strcmp(name, "-") == 0) {
  575.         name = "standard input";
  576.         fp = stdin;
  577.     } else if ((fp = fopen(name, "r")) == NULL) {
  578.         (void) fprintf(stderr, "%s: Can't open ", progname);
  579.         perror(name);
  580.         exit(1);
  581.     }
  582.     wantcont = FALSE;
  583.     for (num = 1; ; ++num) {
  584.         eat(name, num);
  585.         if (fgets(buf, sizeof buf, fp) != buf)
  586.             break;
  587.         cp = index(buf, '\n');
  588.         if (cp == NULL) {
  589.             error("line too long");
  590.             exit(1);
  591.         }
  592.         *cp = '\0';
  593.         fields = getfields(buf);
  594.         nfields = 0;
  595.         while (fields[nfields] != NULL) {
  596.             if (ciequal(fields[nfields], "-"))
  597.                 fields[nfields] = "";
  598.             ++nfields;
  599.         }
  600.         if (nfields == 0) {
  601.             /* nothing to do */
  602.         } else if (wantcont) {
  603.             wantcont = inzcont(fields, nfields);
  604.         } else {
  605.             lp = byword(fields[0], line_codes);
  606.             if (lp == NULL)
  607.                 error("input line of unknown type");
  608.             else switch ((int) (lp->l_value)) {
  609.                 case LC_RULE:
  610.                     inrule(fields, nfields);
  611.                     wantcont = FALSE;
  612.                     break;
  613.                 case LC_ZONE:
  614.                     wantcont = inzone(fields, nfields);
  615.                     break;
  616.                 case LC_LINK:
  617.                     inlink(fields, nfields);
  618.                     wantcont = FALSE;
  619.                     break;
  620.                 default:    /* "cannot happen" */
  621.                     (void) fprintf(stderr,
  622. "%s: panic: Invalid l_value %d\n",
  623.                         progname, lp->l_value);
  624.                     exit(1);
  625.             }
  626.         }
  627.         free((char *) fields);
  628.     }
  629.     if (ferror(fp)) {
  630.         (void) fprintf(stderr, "%s: Error reading ", progname);
  631.         perror(filename);
  632.         exit(1);
  633.     }
  634.     if (fp != stdin && fclose(fp)) {
  635.         (void) fprintf(stderr, "%s: Error closing ", progname);
  636.         perror(filename);
  637.         exit(1);
  638.     }
  639.     if (wantcont)
  640.         error("expected continuation line not found");
  641. }
  642.  
  643. /*
  644. ** Convert a string of one of the forms
  645. **    h    -h     hh:mm    -hh:mm    hh:mm:ss    -hh:mm:ss
  646. ** into a number of seconds.
  647. ** A null string maps to zero.
  648. ** Call error with errstring and return zero on errors.
  649. */
  650.  
  651. static long
  652. gethms(string, errstring, signable)
  653. char *    string;
  654. char *    errstring;
  655. {
  656.     int    hh, mm, ss, sign;
  657.  
  658.     if (string == NULL || *string == '\0')
  659.         return 0;
  660.     if (!signable)
  661.         sign = 1;
  662.     else if (*string == '-') {
  663.         sign = -1;
  664.         ++string;
  665.     } else    sign = 1;
  666.     if (sscanf(string, scheck(string, "%d"), &hh) == 1)
  667.         mm = ss = 0;
  668.     else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2)
  669.         ss = 0;
  670.     else if (sscanf(string, scheck(string, "%d:%d:%d"),
  671.         &hh, &mm, &ss) != 3) {
  672.             error(errstring);
  673.             return 0;
  674.     }
  675.     if (hh < 0 || hh >= HOURS_PER_DAY ||
  676.         mm < 0 || mm >= MINS_PER_HOUR ||
  677.         ss < 0 || ss >= SECS_PER_MIN) {
  678.             error(errstring);
  679.             return 0;
  680.     }
  681.     return eitol(sign) *
  682.         (eitol(hh * MINS_PER_HOUR + mm) *
  683.         eitol(SECS_PER_MIN) + eitol(ss));
  684. }
  685.  
  686. static
  687. inrule(fields, nfields)
  688. register char **    fields;
  689. {
  690.     struct rule    r;
  691.  
  692.     if (nfields != RULE_FIELDS) {
  693.         error("wrong number of fields on Rule line");
  694.         return;
  695.     }
  696.     if (*fields[RF_NAME] == '\0') {
  697.         error("nameless rule");
  698.         return;
  699.     }
  700.     r.r_filename = filename;
  701.     r.r_linenum = linenum;
  702.     r.r_stdoff = gethms(fields[RF_STDOFF], "invalid saved time", TRUE);
  703.     rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
  704.         fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
  705.     r.r_name = ecpyalloc(fields[RF_NAME]);
  706.     r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
  707.     rules = (struct rule *) erealloc((char *) rules,
  708.         (nrules + 1) * sizeof *rules);
  709.     rules[nrules++] = r;
  710. }
  711.  
  712. static
  713. inzone(fields, nfields)
  714. register char **    fields;
  715. {
  716.     register int    i;
  717.     char        buf[132];
  718.  
  719.     if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
  720.         error("wrong number of fields on Zone line");
  721.         return FALSE;
  722.     }
  723.     if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
  724.         (void) sprintf(buf,
  725.             "\"Zone %s\" line and -l option are mutually exclusive",
  726.             TZDEFAULT);
  727.         error(buf);
  728.         return FALSE;
  729.     }
  730.     for (i = 0; i < nzones; ++i)
  731.         if (zones[i].z_name != NULL &&
  732.             strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
  733.                 (void) sprintf(buf,
  734. "duplicate zone name %s (file \"%s\", line %d)",
  735.                     fields[ZF_NAME],
  736.                     zones[i].z_filename,
  737.                     zones[i].z_linenum);
  738.                 error(buf);
  739.                 return FALSE;
  740.         }
  741.     return inzsub(fields, nfields, FALSE);
  742. }
  743.  
  744. static
  745. inzcont(fields, nfields)
  746. register char **    fields;
  747. {
  748.     if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
  749.         error("wrong number of fields on Zone continuation line");
  750.         return FALSE;
  751.     }
  752.     return inzsub(fields, nfields, TRUE);
  753. }
  754.  
  755. static
  756. inzsub(fields, nfields, iscont)
  757. register char **    fields;
  758. {
  759.     register char *    cp;
  760.     struct zone    z;
  761.     register int    i_gmtoff, i_rule, i_format;
  762.     register int    i_untilyear, i_untilmonth;
  763.     register int    i_untilday, i_untiltime;
  764.     register int    hasuntil;
  765.  
  766.     if (iscont) {
  767.         i_gmtoff = ZFC_GMTOFF;
  768.         i_rule = ZFC_RULE;
  769.         i_format = ZFC_FORMAT;
  770.         i_untilyear = ZFC_UNTILYEAR;
  771.         i_untilmonth = ZFC_UNTILMONTH;
  772.         i_untilday = ZFC_UNTILDAY;
  773.         i_untiltime = ZFC_UNTILTIME;
  774.         z.z_name = NULL;
  775.     } else {
  776.         i_gmtoff = ZF_GMTOFF;
  777.         i_rule = ZF_RULE;
  778.         i_format = ZF_FORMAT;
  779.         i_untilyear = ZF_UNTILYEAR;
  780.         i_untilmonth = ZF_UNTILMONTH;
  781.         i_untilday = ZF_UNTILDAY;
  782.         i_untiltime = ZF_UNTILTIME;
  783.         z.z_name = ecpyalloc(fields[ZF_NAME]);
  784.     }
  785.     z.z_filename = filename;
  786.     z.z_linenum = linenum;
  787.     z.z_gmtoff = gethms(fields[i_gmtoff], "invalid GMT offset", TRUE);
  788.     if ((cp = index(fields[i_format], '%')) != 0) {
  789.         if (*++cp != 's' || index(cp, '%') != 0) {
  790.             error("invalid abbreviation format");
  791.             return FALSE;
  792.         }
  793.     }
  794.     z.z_rule = ecpyalloc(fields[i_rule]);
  795.     z.z_format = ecpyalloc(fields[i_format]);
  796.     hasuntil = nfields > i_untilyear;
  797.     if (hasuntil) {
  798.         z.z_untilrule.r_filename = filename;
  799.         z.z_untilrule.r_linenum = linenum;
  800.         rulesub(&z.z_untilrule,
  801.             fields[i_untilyear],
  802.             "only",
  803.             "",
  804.             (nfields > i_untilmonth) ? fields[i_untilmonth] : "Jan",
  805.             (nfields > i_untilday) ? fields[i_untilday] : "1",
  806.             (nfields > i_untiltime) ? fields[i_untiltime] : "0");
  807.         z.z_untiltime = rpytime(&z.z_untilrule, z.z_untilrule.r_loyear);
  808.         if (iscont && nzones > 0 && z.z_untiltime < max_time &&
  809.             z.z_untiltime > min_time &&
  810.             zones[nzones - 1].z_untiltime >= z.z_untiltime) {
  811. error("Zone continuation line end time is not after end time of previous line");
  812.             return FALSE;
  813.         }
  814.     }
  815.     zones = (struct zone *) erealloc((char *) zones,
  816.         (nzones + 1) * sizeof *zones);
  817.     zones[nzones++] = z;
  818.     /*
  819.     ** If there was an UNTIL field on this line,
  820.     ** there's more information about the zone on the next line.
  821.     */
  822.     return hasuntil;
  823. }
  824.  
  825. static
  826. inlink(fields, nfields)
  827. register char **    fields;
  828. {
  829.     struct link    l;
  830.  
  831.     if (nfields != LINK_FIELDS) {
  832.         error("wrong number of fields on Link line");
  833.         return;
  834.     }
  835.     if (*fields[LF_FROM] == '\0') {
  836.         error("blank FROM field on Link line");
  837.         return;
  838.     }
  839.     if (*fields[LF_TO] == '\0') {
  840.         error("blank TO field on Link line");
  841.         return;
  842.     }
  843.     l.l_filename = filename;
  844.     l.l_linenum = linenum;
  845.     l.l_from = ecpyalloc(fields[LF_FROM]);
  846.     l.l_to = ecpyalloc(fields[LF_TO]);
  847.     links = (struct link *) erealloc((char *) links,
  848.         (nlinks + 1) * sizeof *links);
  849.     links[nlinks++] = l;
  850. }
  851.  
  852. static
  853. rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep)
  854. register struct rule *    rp;
  855. char *            loyearp;
  856. char *            hiyearp;
  857. char *            typep;
  858. char *            monthp;
  859. char *            dayp;
  860. char *            timep;
  861. {
  862.     register struct lookup *    lp;
  863.     register char *            cp;
  864.  
  865.     if ((lp = byword(monthp, mon_names)) == NULL) {
  866.         error("invalid month name");
  867.         return;
  868.     }
  869.     rp->r_month = lp->l_value;
  870.     rp->r_todisstd = FALSE;
  871.     cp = timep;
  872.     if (*cp != '\0') {
  873.         cp += strlen(cp) - 1;
  874.         switch (lowerit(*cp)) {
  875.             case 's':
  876.                 rp->r_todisstd = TRUE;
  877.                 *cp = '\0';
  878.                 break;
  879.             case 'w':
  880.                 rp->r_todisstd = FALSE;
  881.                 *cp = '\0';
  882.                 break;
  883.         }
  884.     }
  885.     rp->r_tod = gethms(timep, "invalid time of day", FALSE);
  886.     /*
  887.     ** Year work.
  888.     */
  889.     cp = loyearp;
  890.     if ((lp = byword(cp, begin_years)) != NULL) switch ((int) lp->l_value) {
  891.         case YR_MINIMUM:
  892.             rp->r_loyear = min_year;
  893.             break;
  894.         case YR_MAXIMUM:
  895.             rp->r_loyear = max_year;
  896.             break;
  897.         default:    /* "cannot happen" */
  898.             (void) fprintf(stderr,
  899.                 "%s: panic: Invalid l_value %d\n",
  900.                 progname, lp->l_value);
  901.             exit(1);
  902.     } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1 ||
  903.         rp->r_loyear < min_year || rp->r_loyear > max_year) {
  904.             if (noise)
  905.                 error("invalid starting year");
  906.             if (rp->r_loyear > max_year)
  907.                 return;
  908.     }
  909.     cp = hiyearp;
  910.     if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) {
  911.         case YR_MINIMUM:
  912.             rp->r_hiyear = min_year;
  913.             break;
  914.         case YR_MAXIMUM:
  915.             rp->r_hiyear = max_year;
  916.             break;
  917.         case YR_ONLY:
  918.             rp->r_hiyear = rp->r_loyear;
  919.             break;
  920.         default:    /* "cannot happen" */
  921.             (void) fprintf(stderr,
  922.                 "%s: panic: Invalid l_value %d\n",
  923.                 progname, lp->l_value);
  924.             exit(1);
  925.     } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1 ||
  926.         rp->r_hiyear < min_year || rp->r_hiyear > max_year) {
  927.             if (noise)
  928.                 error("invalid ending year");
  929.             if (rp->r_hiyear < min_year)
  930.                 return;
  931.     }
  932.     if (rp->r_hiyear < min_year)
  933.          return;
  934.      if (rp->r_loyear < min_year)
  935.          rp->r_loyear = min_year;
  936.      if (rp->r_hiyear > max_year)
  937.          rp->r_hiyear = max_year;
  938.     if (rp->r_loyear > rp->r_hiyear) {
  939.         error("starting year greater than ending year");
  940.         return;
  941.     }
  942.     if (*typep == '\0')
  943.         rp->r_yrtype = NULL;
  944.     else {
  945.         if (rp->r_loyear == rp->r_hiyear) {
  946.             error("typed single year");
  947.             return;
  948.         }
  949.         rp->r_yrtype = ecpyalloc(typep);
  950.     }
  951.     /*
  952.     ** Day work.
  953.     ** Accept things such as:
  954.     **    1
  955.     **    last-Sunday
  956.     **    Sun<=20
  957.     **    Sun>=7
  958.     */
  959.     if ((lp = byword(dayp, lasts)) != NULL) {
  960.         rp->r_dycode = DC_DOWLEQ;
  961.         rp->r_wday = lp->l_value;
  962.         rp->r_dayofmonth = len_months[1][rp->r_month];
  963.     } else {
  964.         if ((cp = index(dayp, '<')) != 0)
  965.             rp->r_dycode = DC_DOWLEQ;
  966.         else if ((cp = index(dayp, '>')) != 0)
  967.             rp->r_dycode = DC_DOWGEQ;
  968.         else {
  969.             cp = dayp;
  970.             rp->r_dycode = DC_DOM;
  971.         }
  972.         if (rp->r_dycode != DC_DOM) {
  973.             *cp++ = 0;
  974.             if (*cp++ != '=') {
  975.                 error("invalid day of month");
  976.                 return;
  977.             }
  978.             if ((lp = byword(dayp, wday_names)) == NULL) {
  979.                 error("invalid weekday name");
  980.                 return;
  981.             }
  982.             rp->r_wday = lp->l_value;
  983.         }
  984.         if (sscanf(cp, scheck(cp, "%d"), &rp->r_dayofmonth) != 1 ||
  985.             rp->r_dayofmonth <= 0 ||
  986.             (rp->r_dayofmonth > len_months[1][rp->r_month])) {
  987.                 error("invalid day of month");
  988.                 return;
  989.         }
  990.     }
  991. }
  992.  
  993. static
  994. puttzcode(val, fp)
  995. long    val;
  996. FILE *    fp;
  997. {
  998.     register int    c;
  999.     register int    shift;
  1000.  
  1001.     for (shift = 24; shift >= 0; shift -= 8) {
  1002.         c = val >> shift;
  1003.         (void) putc(c, fp);
  1004.     }
  1005. }
  1006.  
  1007. static
  1008. writezone(name)
  1009. char *    name;
  1010. {
  1011.     register FILE *        fp;
  1012.     register int        i;
  1013.     char            fullname[BUFSIZ];
  1014.  
  1015.     if (strlen(directory) + 1 + strlen(name) >= sizeof fullname) {
  1016.         (void) fprintf(stderr,
  1017.             "%s: File name %s/%s too long\n", progname,
  1018.             directory, name);
  1019.         exit(1);
  1020.     }
  1021.     (void) sprintf(fullname, "%s/%s", directory, name);
  1022.     if ((fp = fopen(fullname, "w")) == NULL) {
  1023.         if (mkdirs(fullname) != 0)
  1024.             exit(1);
  1025.         if ((fp = fopen(fullname, "w")) == NULL) {
  1026.             (void) fprintf(stderr, "%s: Can't create ", progname);
  1027.             perror(fullname);
  1028.             exit(1);
  1029.         }
  1030.     }
  1031.     (void) fseek(fp, (long) sizeof ((struct tzhead *) 0)->tzh_reserved, 0);
  1032.     puttzcode(eitol(timecnt), fp);
  1033.     puttzcode(eitol(typecnt), fp);
  1034.     puttzcode(eitol(charcnt), fp);
  1035.     for (i = 0; i < timecnt; ++i)
  1036.         puttzcode((long) ats[i], fp);
  1037.     if (timecnt > 0)
  1038.         (void) fwrite((char *) types, sizeof types[0],
  1039.             (int) timecnt, fp);
  1040.     for (i = 0; i < typecnt; ++i) {
  1041.         puttzcode((long) gmtoffs[i], fp);
  1042.         (void) putc(isdsts[i], fp);
  1043.         (void) putc(abbrinds[i], fp);
  1044.     }
  1045.     if (charcnt != 0)
  1046.         (void) fwrite(chars, sizeof chars[0], (int) charcnt, fp);
  1047.     if (ferror(fp) || fclose(fp)) {
  1048.         (void) fprintf(stderr, "%s: Write error on ", progname);
  1049.         perror(fullname);
  1050.         exit(1);
  1051.     }
  1052. }
  1053.  
  1054. static
  1055. outzone(zpfirst, zonecount)
  1056. struct zone *    zpfirst;
  1057. {
  1058.     register struct zone *        zp;
  1059.     register struct rule *        rp;
  1060.     register int            i, j;
  1061.     register int            usestart, useuntil;
  1062.     register time_t            starttime, untiltime;
  1063.     register long            gmtoff;
  1064.     register long            stdoff;
  1065.     register int            year;
  1066.     register long            startoff;
  1067.     register int            startisdst;
  1068.     register int            type;
  1069.     char                startbuf[BUFSIZ];
  1070.  
  1071.     /*
  1072.     ** Now. . .finally. . .generate some useful data!
  1073.     */
  1074.     timecnt = 0;
  1075.     typecnt = 0;
  1076.     charcnt = 0;
  1077.     /*
  1078.     ** Two guesses. . .the second may well be corrected later.
  1079.     */
  1080.     gmtoff = zpfirst->z_gmtoff;
  1081.     stdoff = 0;
  1082.     for (i = 0; i < zonecount; ++i) {
  1083.         usestart = i > 0;
  1084.         useuntil = i < (zonecount - 1);
  1085.         zp = &zpfirst[i];
  1086.         eat(zp->z_filename, zp->z_linenum);
  1087.         startisdst = -1;
  1088.         if (zp->z_nrules == 0) {
  1089.             type = addtype(oadd(zp->z_gmtoff, zp->z_stdoff),
  1090.                 zp->z_format, zp->z_stdoff != 0);
  1091.             if (usestart)
  1092.                 addtt(starttime, type);
  1093.             gmtoff = zp->z_gmtoff;
  1094.             stdoff = zp->z_stdoff;
  1095.         } else for (year = min_year; year <= max_year; ++year) {
  1096.             if (useuntil && year > zp->z_untilrule.r_hiyear)
  1097.                 break;
  1098.             /*
  1099.             ** Mark which rules to do in the current year.
  1100.             ** For those to do, calculate rpytime(rp, year);
  1101.             */
  1102.             for (j = 0; j < zp->z_nrules; ++j) {
  1103.                 rp = &zp->z_rules[j];
  1104.                 eats(zp->z_filename, zp->z_linenum,
  1105.                     rp->r_filename, rp->r_linenum);
  1106.                 rp->r_todo = year >= rp->r_loyear &&
  1107.                         year <= rp->r_hiyear &&
  1108.                         yearistype(year, rp->r_yrtype);
  1109.                 if (rp->r_todo)
  1110.                     rp->r_temp = rpytime(rp, year);
  1111.             }
  1112.             for ( ; ; ) {
  1113.                 register int    k;
  1114.                 register time_t    jtime, ktime;
  1115.                 register long    offset;
  1116.                 char        buf[BUFSIZ];
  1117.  
  1118.                 if (useuntil) {
  1119.                     /*
  1120.                     ** Turn untiltime into GMT
  1121.                     ** assuming the current gmtoff and
  1122.                     ** stdoff values.
  1123.                     */
  1124.                     offset = gmtoff;
  1125.                     if (!zp->z_untilrule.r_todisstd)
  1126.                         offset = oadd(offset, stdoff);
  1127.                     untiltime = tadd(zp->z_untiltime,
  1128.                         -offset);
  1129.                 }
  1130.                 /*
  1131.                 ** Find the rule (of those to do, if any)
  1132.                 ** that takes effect earliest in the year.
  1133.                 */
  1134.                 k = -1;
  1135.                 for (j = 0; j < zp->z_nrules; ++j) {
  1136.                     rp = &zp->z_rules[j];
  1137.                     if (!rp->r_todo)
  1138.                         continue;
  1139.                     eats(zp->z_filename, zp->z_linenum,
  1140.                         rp->r_filename, rp->r_linenum);
  1141.                     offset = gmtoff;
  1142.                     if (!rp->r_todisstd)
  1143.                         offset = oadd(offset, stdoff);
  1144.                     jtime = rp->r_temp;
  1145.                     if (jtime == min_time ||
  1146.                         jtime == max_time)
  1147.                             continue;
  1148.                     jtime = tadd(jtime, -offset);
  1149.                     if (k < 0 || jtime < ktime) {
  1150.                         k = j;
  1151.                         ktime = jtime;
  1152.                     }
  1153.                 }
  1154.                 if (k < 0)
  1155.                     break;    /* go on to next year */
  1156.                 rp = &zp->z_rules[k];
  1157.                 rp->r_todo = FALSE;
  1158.                 if (useuntil && ktime >= untiltime)
  1159.                     break;
  1160.                 if (usestart) {
  1161.                     if (ktime < starttime) {
  1162.                         stdoff = rp->r_stdoff;
  1163.                         startoff = oadd(zp->z_gmtoff,
  1164.                             rp->r_stdoff);
  1165.                         (void) sprintf(startbuf,
  1166.                             zp->z_format,
  1167.                             rp->r_abbrvar);
  1168.                         startisdst =
  1169.                             rp->r_stdoff != 0;
  1170.                         continue;
  1171.                     }
  1172.                     if (ktime != starttime &&
  1173.                         startisdst >= 0)
  1174. addtt(starttime, addtype(startoff, startbuf, startisdst));
  1175.                     usestart = FALSE;
  1176.                 }
  1177.                 eats(zp->z_filename, zp->z_linenum,
  1178.                     rp->r_filename, rp->r_linenum);
  1179.                 (void) sprintf(buf, zp->z_format,
  1180.                     rp->r_abbrvar);
  1181.                 offset = oadd(zp->z_gmtoff, rp->r_stdoff);
  1182.                 type = addtype(offset, buf, rp->r_stdoff != 0);
  1183.                 if (timecnt != 0 || rp->r_stdoff != 0)
  1184.                     addtt(ktime, type);
  1185.                 gmtoff = zp->z_gmtoff;
  1186.                 stdoff = rp->r_stdoff;
  1187.             }
  1188.         }
  1189.         /*
  1190.         ** Now we may get to set starttime for the next zone line.
  1191.         */
  1192.         if (useuntil)
  1193.             starttime = tadd(zp->z_untiltime,
  1194.                 -gmtoffs[types[timecnt - 1]]);
  1195.     }
  1196.     writezone(zpfirst->z_name);
  1197. }
  1198.  
  1199. static
  1200. addtt(starttime, type)
  1201. time_t    starttime;
  1202. {
  1203.     if (timecnt != 0 && type == types[timecnt - 1])
  1204.         return;    /* easy enough! */
  1205.     if (timecnt >= TZ_MAX_TIMES) {
  1206.         error("too many transitions?!");
  1207.         exit(1);
  1208.     }
  1209.     ats[timecnt] = starttime;
  1210.     types[timecnt] = type;
  1211.     ++timecnt;
  1212. }
  1213.  
  1214. static
  1215. addtype(gmtoff, abbr, isdst)
  1216. long    gmtoff;
  1217. char *    abbr;
  1218. {
  1219.     register int    i, j;
  1220.  
  1221.     /*
  1222.     ** See if there's already an entry for this zone type.
  1223.     ** If so, just return its index.
  1224.     */
  1225.     for (i = 0; i < typecnt; ++i) {
  1226.         if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
  1227.             strcmp(abbr, &chars[abbrinds[i]]) == 0)
  1228.                 return i;
  1229.     }
  1230.     /*
  1231.     ** There isn't one; add a new one, unless there are already too
  1232.     ** many.
  1233.     */
  1234.     if (typecnt >= TZ_MAX_TYPES) {
  1235.         error("too many local time types");
  1236.         exit(1);
  1237.     }
  1238.     gmtoffs[i] = gmtoff;
  1239.     isdsts[i] = isdst;
  1240.  
  1241.     for (j = 0; j < charcnt; ++j)
  1242.         if (strcmp(&chars[j], abbr) == 0)
  1243.             break;
  1244.     if (j == charcnt)
  1245.         newabbr(abbr);
  1246.     abbrinds[i] = j;
  1247.     ++typecnt;
  1248.     return i;
  1249. }
  1250.  
  1251. static
  1252. yearistype(year, type)
  1253. char *    type;
  1254. {
  1255.     char    buf[BUFSIZ];
  1256.     int    result;
  1257.  
  1258.     if (type == NULL || *type == '\0')
  1259.         return TRUE;
  1260.     if (strcmp(type, "uspres") == 0)
  1261.         return (year % 4) == 0;
  1262.     if (strcmp(type, "nonpres") == 0)
  1263.         return (year % 4) != 0;
  1264.     (void) sprintf(buf, "yearistype %d %s", year, type);
  1265.     result = system(buf);
  1266.     if (result == 0)
  1267.         return TRUE;
  1268.     if (result == 1 << 8)
  1269.         return FALSE;
  1270.     error("Wild result from command execution");
  1271.     (void) fprintf(stderr, "%s: command was '%s', result was %d\n",
  1272.         progname, buf, result);
  1273.     for ( ; ; )
  1274.         exit(1);
  1275. }
  1276.  
  1277. static
  1278. lowerit(a)
  1279. {
  1280.     return (isascii(a) && isupper(a)) ? tolower(a) : a;
  1281. }
  1282.  
  1283. static
  1284. ciequal(ap, bp)        /* case-insensitive equality */
  1285. register char *    ap;
  1286. register char *    bp;
  1287. {
  1288.     while (lowerit(*ap) == lowerit(*bp++))
  1289.         if (*ap++ == '\0')
  1290.             return TRUE;
  1291.     return FALSE;
  1292. }
  1293.  
  1294. static
  1295. isabbr(abbr, word)
  1296. register char *    abbr;
  1297. register char *    word;
  1298. {
  1299.     if (lowerit(*abbr) != lowerit(*word))
  1300.         return FALSE;
  1301.     ++word;
  1302.     while (*++abbr != '\0')
  1303.         do if (*word == '\0')
  1304.             return FALSE;
  1305.                 while (lowerit(*word++) != lowerit(*abbr));
  1306.     return TRUE;
  1307. }
  1308.  
  1309. static struct lookup *
  1310. byword(word, table)
  1311. register char *            word;
  1312. register struct lookup *    table;
  1313. {
  1314.     register struct lookup *    foundlp;
  1315.     register struct lookup *    lp;
  1316.  
  1317.     if (word == NULL || table == NULL)
  1318.         return NULL;
  1319.     /*
  1320.     ** Look for exact match.
  1321.     */
  1322.     for (lp = table; lp->l_word != NULL; ++lp)
  1323.         if (ciequal(word, lp->l_word))
  1324.             return lp;
  1325.     /*
  1326.     ** Look for inexact match.
  1327.     */
  1328.     foundlp = NULL;
  1329.     for (lp = table; lp->l_word != NULL; ++lp)
  1330.         if (isabbr(word, lp->l_word))
  1331.             if (foundlp == NULL)
  1332.                 foundlp = lp;
  1333.             else    return NULL;    /* multiple inexact matches */
  1334.     return foundlp;
  1335. }
  1336.  
  1337. static char **
  1338. getfields(cp)
  1339. register char *    cp;
  1340. {
  1341.     register char *        dp;
  1342.     register char **    array;
  1343.     register int        nsubs;
  1344.  
  1345.     if (cp == NULL)
  1346.         return NULL;
  1347.     array = (char **) emalloc((strlen(cp) + 1) * sizeof *array);
  1348.     nsubs = 0;
  1349.     for ( ; ; ) {
  1350.         while (isascii(*cp) && isspace(*cp))
  1351.             ++cp;
  1352.         if (*cp == '\0' || *cp == '#')
  1353.             break;
  1354.         array[nsubs++] = dp = cp;
  1355.         do {
  1356.             if ((*dp = *cp++) != '"')
  1357.                 ++dp;
  1358.             else while ((*dp = *cp++) != '"')
  1359.                 if (*dp != '\0')
  1360.                     ++dp;
  1361.                 else    error("Odd number of quotation marks");
  1362.         } while (*cp != '\0' && *cp != '#' &&
  1363.             (!isascii(*cp) || !isspace(*cp)));
  1364.         if (isascii(*cp) && isspace(*cp))
  1365.             ++cp;
  1366.         *dp = '\0';
  1367.     }
  1368.     array[nsubs] = NULL;
  1369.     return array;
  1370. }
  1371.  
  1372. static long
  1373. oadd(t1, t2)
  1374. long    t1;
  1375. long    t2;
  1376. {
  1377.     register long    t;
  1378.  
  1379.     t = t1 + t2;
  1380.     if (t2 > 0 && t <= t1 || t2 < 0 && t >= t1) {
  1381.         error("time overflow");
  1382.         exit(1);
  1383.     }
  1384.     return t;
  1385. }
  1386.  
  1387. static time_t
  1388. tadd(t1, t2)
  1389. time_t    t1;
  1390. long    t2;
  1391. {
  1392.     register time_t    t;
  1393.  
  1394.     if (t1 == max_time && t2 > 0)
  1395.         return max_time;
  1396.     if (t1 == min_time && t2 < 0)
  1397.         return min_time;
  1398.     t = t1 + t2;
  1399.     if (t2 > 0 && t <= t1 || t2 < 0 && t >= t1) {
  1400.         error("time overflow");
  1401.         exit(1);
  1402.     }
  1403.     return t;
  1404. }
  1405.  
  1406. /*
  1407. ** Given a rule, and a year, compute the date - in seconds since January 1,
  1408. ** 1970, 00:00 LOCAL time - in that year that the rule refers to.
  1409. */
  1410.  
  1411. static time_t
  1412. rpytime(rp, wantedy)
  1413. register struct rule *    rp;
  1414. register int        wantedy;
  1415. {
  1416.     register int    y, m, i;
  1417.     register long    dayoff;            /* with a nod to Margaret O. */
  1418.     register time_t    t;
  1419.  
  1420.     dayoff = 0;
  1421.     m = TM_JANUARY;
  1422.     y = EPOCH_YEAR;
  1423.     while (wantedy != y) {
  1424.         if (wantedy > y) {
  1425.             i = len_years[isleap(y)];
  1426.             ++y;
  1427.         } else {
  1428.             --y;
  1429.             i = -len_years[isleap(y)];
  1430.         }
  1431.         dayoff = oadd(dayoff, eitol(i));
  1432.     }
  1433.     while (m != rp->r_month) {
  1434.         i = len_months[isleap(y)][m];
  1435.         dayoff = oadd(dayoff, eitol(i));
  1436.         ++m;
  1437.     }
  1438.     i = rp->r_dayofmonth;
  1439.     if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
  1440.         if (rp->r_dycode == DC_DOWLEQ)
  1441.             --i;
  1442.         else {
  1443.             error("use of 2/29 in non leap-year");
  1444.             exit(1);
  1445.         }
  1446.     }
  1447.     --i;
  1448.     dayoff = oadd(dayoff, eitol(i));
  1449.     if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
  1450.         register long    wday;
  1451.  
  1452. #define LDAYS_PER_WEEK    ((long) DAYS_PER_WEEK)
  1453.         wday = eitol(EPOCH_WDAY);
  1454.         /*
  1455.         ** Don't trust mod of negative numbers.
  1456.         */
  1457.         if (dayoff >= 0)
  1458.             wday = (wday + dayoff) % LDAYS_PER_WEEK;
  1459.         else {
  1460.             wday -= ((-dayoff) % LDAYS_PER_WEEK);
  1461.             if (wday < 0)
  1462.                 wday += LDAYS_PER_WEEK;
  1463.         }
  1464.         while (wday != eitol(rp->r_wday))
  1465.             if (rp->r_dycode == DC_DOWGEQ) {
  1466.                 dayoff = oadd(dayoff, (long) 1);
  1467.                 if (++wday >= LDAYS_PER_WEEK)
  1468.                     wday = 0;
  1469.                 ++i;
  1470.             } else {
  1471.                 dayoff = oadd(dayoff, (long) -1);
  1472.                 if (--wday < 0)
  1473.                     wday = LDAYS_PER_WEEK;
  1474.                 --i;
  1475.             }
  1476.         if (i < 0 || i >= len_months[isleap(y)][m]) {
  1477.             error("no day in month matches rule");
  1478.             exit(1);
  1479.         }
  1480.     }
  1481.     if (dayoff < 0 && !tt_signed) {
  1482.         if (wantedy == rp->r_loyear)
  1483.             return min_time;
  1484.         error("time before zero");
  1485.         exit(1);
  1486.     }
  1487.     t = (time_t) dayoff * SECS_PER_DAY;
  1488.     /*
  1489.     ** Cheap overflow check.
  1490.     */
  1491.     if (t / SECS_PER_DAY != dayoff) {
  1492.         if (wantedy == rp->r_hiyear)
  1493.             return max_time;
  1494.         if (wantedy == rp->r_loyear)
  1495.             return min_time;
  1496.         error("time overflow");
  1497.         exit(1);
  1498.     }
  1499.     return tadd(t, rp->r_tod);
  1500. }
  1501.  
  1502. static
  1503. newabbr(string)
  1504. char *    string;
  1505. {
  1506.     register int    i;
  1507.  
  1508.     i = strlen(string) + 1;
  1509.     if (charcnt + i >= TZ_MAX_CHARS) {
  1510.         error("too many, or too long, time zone abbreviations");
  1511.         exit(1);
  1512.     }
  1513.     (void) strcpy(&chars[charcnt], string);
  1514.     charcnt += eitol(i);
  1515. }
  1516.  
  1517. static
  1518. mkdirs(name)
  1519. char *    name;
  1520. {
  1521.     register char *    cp;
  1522.  
  1523.     if ((cp = name) == NULL || *cp == '\0')
  1524.         return 0;
  1525.     while ((cp = index(cp + 1, '/')) != 0) {
  1526.         *cp = '\0';
  1527.         if (access(name, 0) != 0) {
  1528.             /*
  1529.              * It doesn't seem to exist, so we try to create it.
  1530.              */
  1531.             if (mkdir(name, 0755) != 0) {
  1532.                 (void) fprintf(stderr,
  1533.                     "%s: Can't create directory ",
  1534.                     progname);
  1535.                 perror(name);
  1536.                 return -1;
  1537.             }
  1538.         }
  1539.         *cp = '/';
  1540.     }
  1541.     return 0;
  1542. }
  1543.  
  1544. static long
  1545. eitol(i)
  1546. {
  1547.     long    l;
  1548.  
  1549.     l = i;
  1550.     if (i < 0 && l >= 0 || i == 0 && l != 0 || i > 0 && l <= 0) {
  1551.         (void) fprintf(stderr, "%s: %d did not sign extend correctly\n",
  1552.             progname, i);
  1553.         exit(1);
  1554.     }
  1555.     return l;
  1556. }
  1557.  
  1558. /*
  1559. ** UNIX is a registered trademark of AT&T.
  1560. */
  1561.